package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AlipyFeignApi;
import cn.wolfcode.feign.IntergralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {


    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;

    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private AlipyFeignApi alipyFeignApi;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IntergralFeignApi intergralFeignApi;



    @Override
    @Transactional
    public String doSeckill(Long seckillId, int time, Long phone) {
        // 真实库存 -1
        int count = seckillProductService.descStock(seckillId);
        if (count == 0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER); // "您来晚了，商品已经被抢购完毕."
        }

        OrderInfo orderInfo = new OrderInfo();
        // 获取当前vo对象
        Object voStr = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_PRODUCT_LIST.getRealKey(time + ""), seckillId.toString());
        SeckillProductVo vo = JSON.parseObject(voStr + "", SeckillProductVo.class);

        // 参数传递
        long nextId = IdGenerateUtil.get().nextId();
        orderInfo.setOrderNo(nextId + "");
        orderInfo.setCreateDate(new Date());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setIntergral(vo.getIntergral());
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillId(vo.getId());
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setSeckillTime(vo.getTime());
        orderInfo.setProductCount(vo.getStockCount());

        orderInfo.setUserId(phone);
        // 插入订单数据
        orderInfoMapper.insert(orderInfo);

        // redis中存入用户下单信息
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_ZSET.getRealKey(time + ""), seckillId + ":" + phone);

        return orderInfo.getOrderNo();
    }

    @Override
    public OrderInfo findByOderNo(String orderNo) {
        // return orderInfoMapper.find(orderNo);

        // 使用 canal 实现对数据库的增删改监听, 同时同步到redis中
        // 因而现在查直接在redis查即可, 性能高
        Object orderInfoStr = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        if (orderInfoStr == null){
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        return JSON.parseObject(orderInfoStr.toString(),OrderInfo.class);
    }

    @Override
    public void updateCancelStatus(String orderNo, Integer statusTimeout) {
        orderInfoMapper.updateCancelStatus(orderNo,statusTimeout);
    }

    @Override
    @Transactional
    public String payOnline(String orderNo) {


        // 查询订单
        OrderInfo orderInfo = findByOderNo(orderNo);

        // 插入一条支付的流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);
        payLog.setNotifyTime(orderInfo.getSeckillTime().toString());
        payLog.setOutTradeNo(orderInfo.getProductName());
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLog.setTotalAmount(orderInfo.getSeckillPrice().toString());
        payLogMapper.insert(payLog);

        // 封装 PayVo 参数
        PayVo payVo = new PayVo();
        payVo.setNotifyUrl(notifyUrl);
        payVo.setReturnUrl(returnUrl);

        payVo.setOutTradeNo(orderNo);   // 设置商户订单号
        payVo.setTotalAmount(orderInfo.getSeckillPrice().toString());   // 订单金额
        payVo.setSubject(orderInfo.getProductName());   // 设置订单名称
        payVo.setBody(orderInfo.getProductName());  // 设置订单描述


        // 远程调用支付服务的接口 => 返回跳转页面的json格式数据
        Result<String> result = alipyFeignApi.payOnline(payVo);
        // 获取result封装的数据 并 返回
        if (!result.hasError() && result.getCode() == 200 ){
            return result.getData();
        }
        // 修改订单支付状态
        changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
        return "";
    }

    @Override
    public void changePayStatus(String orderNo, Integer status, Integer paytype) {
        orderInfoMapper.changePayStatus(orderNo,status,paytype);
    }

    @Override
    public void paySuccess(String orderNo) {
        // 查询对应订单
        OrderInfo orderInfo = findByOderNo(orderNo);
        if (orderInfo == null){
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        PayLog payLog = new PayLog();
        payLog.setNotifyTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        payLog.setOutTradeNo(orderNo);
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLog.setTotalAmount(orderInfo.getProductName());
        payLog.setTradeNo(orderNo);
        // 插入流水记录
        payLogMapper.insert(payLog);

        // 修改订单状态
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
    }

    @Override
    public void refundStatus(String orderNo, Integer statusRefund) {
        orderInfoMapper.changeRefundStatus(orderNo,statusRefund);
    }

    @Override
    @GlobalTransactional    // At 模式 & TCC模式
    public void refundIntergral(String orderNo) {

        OrderInfo orderInfo = findByOderNo(orderNo);
        // 插入退款的流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderNo);
        refundLog.setRefundAmount(orderInfo.getSeckillPrice().toString());
        refundLog.setRefundReason("不想要了");
        refundLog.setRefundType(1); // 在线支付退款类型
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);


        // 远程调用实现 积分退款
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setInfo(orderInfo.getProductName());
        vo.setValue(orderInfo.getIntergral());
        vo.setUserId(orderInfo.getUserId());
        vo.setPk(orderNo);
        intergralFeignApi.refundOnIntergral(vo);


        // ===3修改订单状态为退款状态===
        refundStatus(orderNo,OrderInfo.STATUS_REFUND);

        //int i = 1/0;

        // 回补真实库存
        seckillProductService.incrStockCount(orderInfo.getSeckillId());
        // 回补预库存
        seckillProductService.asysBackRedisStockCount(orderInfo.getSeckillId(),orderInfo.getSeckillTime());
        // 修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    @Override
    public void refundOnline(String orderNo) {
        OrderInfo orderInfo = findByOderNo(orderNo);
        // 1插入一条流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderNo);
        refundLog.setRefundAmount(orderInfo.getSeckillPrice().toString());
        refundLog.setRefundReason("不想要了");
        refundLog.setRefundType(0); // 在线支付退款类型
        refundLog.setRefundTime(new Date());
        refundLogMapper.insert(refundLog);

        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderNo);
        refundVo.setRefundAmount(orderInfo.getSeckillPrice().toString());
        refundVo.setRefundReason("不想要了..");
        // 2远程调用支付宝接口 实现退款操作 data 为true 表示退款成功, false表示退款失败
        Result<Boolean> result = alipyFeignApi.refund(refundVo);
        if (result != null && !result.hasError()){
            if (!result.getData()){
                throw new BusinessException(SeckillCodeMsg.REFUND_ERROR);
            }
            // ===3修改订单状态为退款状态===
            refundStatus(orderNo,OrderInfo.STATUS_REFUND);
            // 3补回真实库存
            seckillProductService.incrStockCount(orderInfo.getSeckillId());
            // 4回补预库存
            seckillProductService.asysBackRedisStockCount(orderInfo.getSeckillId(),orderInfo.getSeckillTime());
            // 5修改本地标识
            rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());

        }
    }

    @Override
    @GlobalTransactional
    public String payOnIntergral(String orderNo) {
        OrderInfo orderInfo = findByOderNo(orderNo);
        // 插入一条支付的流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);
        payLog.setNotifyTime(orderInfo.getSeckillTime().toString());
        payLog.setOutTradeNo(orderInfo.getProductName());
        payLog.setPayType(OrderInfo.PAYTYPE_INTERGRAL);
        payLog.setTotalAmount(orderInfo.getSeckillPrice().toString());
        payLogMapper.insert(payLog);

        // 传入积分支付的 vo 对象 ,远程调用积分支付接口
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setPk(orderNo);
        vo.setUserId(orderInfo.getUserId());
        vo.setValue(orderInfo.getIntergral());
        vo.setInfo(orderInfo.getProductName());
        Result<String>  result = intergralFeignApi.payOnIntergral(vo);
        // 获取result封装的数据 并 返回
        if (result.hasError() && result.getCode() != 200 ){
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }

        // 修改订单支付状态
        changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_INTERGRAL);
        return orderNo;
    }



}
